﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Xww.IO {
    /// <summary>实现文件合并、拆分的功能类</summary>
    public static class FileImergeDivide {
        /// <summary>
        /// 按行合并文件
        /// </summary>
        public static void ImergeFiles(string outputFileName, params string[] sourceFiles) {
            if (sourceFiles == null || sourceFiles.Length == 0) return;
            if (!outputFileName.IsValidSaveFilePath())
                throw new ArgumentException(string.Format("{0} does not contain a valid directory.", outputFileName), "Out put file name");

            outputFileName.WriteFileAction(o => {
                foreach (string file in sourceFiles) {
                    foreach (string line in file.ReadAllLines())
                        o.WriteLine(line);
                }
            });
        }
        public static IEnumerable<string> ImergeFiles(this IEnumerable<string> sourceFiles) {
            IEnumerable<string> rst = new string[] { };
            foreach (string fileName in sourceFiles) {
                rst = rst.Concat(fileName.ReadAllLines());
            }
            return rst;
        }
        public static IEnumerable<string> ImergeFiles(this IEnumerable<string> sourceFiles, Encoding encoding) {
            IEnumerable<string> rst = new string[] { };
            foreach (string fileName in sourceFiles) {
                rst = rst.Concat(fileName.ReadAllLines(encoding));
            }
            return rst;
        }
        /// <summary>
        /// 按正负集产生 N Fold 文件
        /// </summary>
        /// <param name="positiveSet">正集数据集</param>
        /// <param name="negativeSet">负集数据集</param>
        /// <param name="nfold">n-fold次数</param>
        public static void GenerateNFoldFiles(string positiveSet, string negativeSet, int nfold, ref string[] outputTrainFiles, ref string[] outputTestFiles) {
            FileInfo[] posFiles = DivideToNFiles(positiveSet, nfold);
            FileInfo[] negativeFiles = DivideToNFiles(negativeSet, nfold);

            //初始化文件名
            if (outputTrainFiles == null || outputTrainFiles.Length != nfold)
                outputTrainFiles = FilePathHelper.GenerateRandomFiles(nfold).Select(o => o.FullName).ToArray();
            if (outputTestFiles == null || outputTestFiles.Length != nfold)
                outputTestFiles = FilePathHelper.GenerateRandomFiles(nfold).Select(o => o.FullName).ToArray();

            for (int i = nfold - 1; i >= 0; i--) {
                List<string> trainSources = new List<string>();
                List<string> testSources = new List<string>();
                for (int j = 0; j < nfold; j++) {
                    if (j == i) {
                        testSources.Add(posFiles[j].FullName);
                        continue;
                    }
                    trainSources.Add(posFiles[j].FullName);
                }
                for (int j = 0; j < nfold; j++) {
                    if (j == i) {
                        testSources.Add(negativeFiles[j].FullName);
                        continue;
                    }
                    trainSources.Add(negativeFiles[j].FullName);
                }
                ImergeFiles(outputTrainFiles[nfold - i - 1], trainSources.ToArray());
                ImergeFiles(outputTestFiles[nfold - i - 1], testSources.ToArray());
            }
            // 删除用到的临时文件 
            posFiles.Union(negativeFiles).ToList().ForEach(o => o.Delete());
        }


        public static FileInfo[] DivideToNFiles(string sourceFile, int nfold) {
            int totalCount = FileReaderWriter.GetLineCount(sourceFile);
            if (totalCount < nfold) throw new Exception(string.Format("指定的文件 {0} 所包含的总行数 {1} 小于NFold数 {2}", sourceFile, totalCount, nfold));
            int equalUnit = totalCount / nfold;

            FileInfo[] rst = FilePathHelper.GenerateRandomFiles(nfold);
            int countIndex = 0;


            StreamWriter writer = null;
            using (writer) {
                foreach (string line in FileReaderWriter.ReadAllLines(sourceFile)) {
                    if (countIndex % equalUnit == 0 && countIndex / equalUnit < nfold) {
                        if (writer != null) writer.Close();
                        writer = rst[countIndex / equalUnit].CreateText();
                    }
                    writer.WriteLine(line);
                    countIndex++;
                }
            }
            return rst;
        }

    }
}